﻿using System;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;

namespace Jacky
{
    public class NodeManager
    {
        private Dictionary<IntVector2, AbstractNode> _nodes = new Dictionary<IntVector2, AbstractNode>();
        
        private List<AbstractNode> _nodeList = new List<AbstractNode>();

        public Action<AbstractNode> OnClickNormalNode;
        
        private List<IntVector2> _landMineNodePosList = new List<IntVector2>();

        public Action<AbstractNode> OnClickLandNode;

        public Action OnSuccessEvent;

        public void Spawn(int width, int height, int landMineCount,Transform parent)
        {
            if (landMineCount > width * height)
            {
                Debug.LogError("地雷数量大于格子数量！");
                return;
            }
            IntVector2[] mineNodePos = new IntVector2[landMineCount];
            for (int i = 0; i < landMineCount; i++)
            {
                int randomX = Random.Range(0, width);
                int randomY = Random.Range(0, height);
                while (!JudgePos(randomX, randomY, mineNodePos))
                {
                    randomX = Random.Range(0, width);
                    randomY = Random.Range(0, height);
                }
                mineNodePos[i] = new IntVector2()
                {
                    x = randomX,y = randomY
                };
            }

           
            for (int i = 0; i < mineNodePos.Length; i++)
            {
                var go = AssetService.LoadAsset("Node");
                go.transform.SetParent(parent);
                go.transform.localScale = Vector3.one;
                go.name = $"LandMine:{mineNodePos[i].x}--{mineNodePos[i].y}";
                var node = GetNodeByType(NodeType.LandMine);
                NodeInitData initData = new NodeInitData()
                {
                    X =  mineNodePos[i].x,Y = mineNodePos[i].y,Value = -1,GObject = go,
                    Pos = NodeHelp.GetPosition(mineNodePos[i].x, mineNodePos[i].y, width,height)
                };
                node.Init(initData);
                node.ClickEvent += OnClickNode;
                _nodes.Add(mineNodePos[i],node);
                _nodeList.Add(node);
                _landMineNodePosList.Add(mineNodePos[i]);
            }

            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    if (_landMineNodePosList.Contains(new IntVector2() {x = i, y = j}))
                    {
                        continue;
                    }

                    int val = CalculateBoundLandMineCount(i, j, width, height);
                    var node = GetNodeByType(NodeType.Normal);
                    var go = AssetService.LoadAsset("Node");
                    go.transform.SetParent(parent);
                    go.transform.localScale = Vector3.one;
                    go.name = $"Normal:{i}--{j}";
                    NodeInitData initData = new NodeInitData()
                    {
                        X =  i,Y = j,Value = val,GObject = go,
                        Pos = NodeHelp.GetPosition(i, j, width,height)
                    };
                    node.Init(initData);
                    node.ClickEvent += OnClickNode;
                    _nodes.Add(new IntVector2(){x = i,y= j}, node);
                    _nodeList.Add(node);
                }
            }
        }

        private bool JudgePos(int x, int y, IntVector2[] arr)
        {
            for (int i = 0; i < arr.Length; i++)
            {
                if (arr[i].x == x && arr[i].y == y)
                {
                    return false;
                }
            }

            return true;
        }

        private int CalculateBoundLandMineCount(int x, int y,int width, int height)
        {
            int count = 0;

            if (_landMineNodePosList.Contains(new IntVector2(){x= x -1,y = y + 1}))
            {
                count++;
            }
            if (_landMineNodePosList.Contains(new IntVector2() {x = x -1, y = y}))
            {
                count++;
            }
            if (_landMineNodePosList.Contains(new IntVector2() {x = x -1, y = y -1}))
            {
                count++;
            }
            if (_landMineNodePosList.Contains(new IntVector2() {x = x, y = y + 1}))
            {
                count++;
            }
            if (_landMineNodePosList.Contains(new IntVector2() {x = x, y = y - 1}))
            {
                count++;
            }
            if (_landMineNodePosList.Contains(new IntVector2() {x = x + 1, y = y + 1}))
            {
                count++;
            }
            if (_landMineNodePosList.Contains(new IntVector2() {x = x + 1, y = y}))
            {
                count++;
            }
            if(_landMineNodePosList.Contains(new IntVector2(){x = x + 1, y = y -1}))
            {
                count++;
            }
            return count;
        }

        private void OnClickNode(AbstractNode node)
        {
            if (node.nType == NodeType.LandMine)
            {
                Debug.LogError($"点击到地雷节点：{node.Data.ToString()}");
                OnClickLandNode?.Invoke(node);
            }
            else
            {
                if (node.nType == NodeType.Normal)
                {
                    Debug.Log($"点击正常节点：{node.Data.ToString()}");
                    HandleOneNormalNode(node);
                    OnClickNormalNode?.Invoke(node);
                }

                if (JudgeIsAllNodeOpened())
                {
                    OnSuccessEvent?.Invoke();
                }
            }
        }

        private bool JudgeIsAllNodeOpened()
        {
            for (int i = 0; i < _nodeList.Count; i++)
            {
                if (!_nodeList[i].IsOpened)
                {
                    return false;
                }
            }

            return true;
        }


        private void HandleOneNormalNode(AbstractNode node)
        {
            if (node.IsOpened)
            {
                return;
            }

            if (node.Data.Value > 0)
            {
                node.ShowValue();
                node.IsOpened = true;
            }
            else
            {
                HandleNormalNode(node);
            }
            
        }
        
        /// <summary>
        /// 处理一个节点周围的节点。如果周围6个节点，有0点，则递归0点周围节点，直到周围节点，没有0点。
        /// </summary>
        /// <param name="node"></param>
        private void HandleNormalNode(AbstractNode node)
        {
            if (node.IsOpened)
            {
                return;
            }
            Debug.Log($"检查节点：{node.Data.ToString()}");
            node.ShowValue();
            node.IsOpened = true;
            int nodeX = node.Data.X;
            int nodeY = node.Data.Y;
            _nodes.TryGetValue(new IntVector2(nodeX - 1, nodeY + 1), out var node1);
            if (node1 != null)
            {
                HandleOneNormalNode(node1);
            }
            _nodes.TryGetValue(new IntVector2(nodeX - 1, nodeY), out var node2);
            if (node2 != null)
            {
                HandleOneNormalNode(node2);
            }
            
            _nodes.TryGetValue(new IntVector2(nodeX - 1, nodeY - 1), out var node3);
            if (node3 != null)
            {
                HandleOneNormalNode(node3);
            }
            
            _nodes.TryGetValue(new IntVector2(nodeX, nodeY + 1), out var node4);
            if (node4 != null)
            {
                HandleOneNormalNode(node4);
            }
            _nodes.TryGetValue(new IntVector2(nodeX, nodeY - 1), out var node5);
            if (node5 != null)
            {
                HandleOneNormalNode(node5);
            }
            _nodes.TryGetValue(new IntVector2(nodeX + 1, nodeY + 1), out var node6);
            if (node6 != null)
            {
                HandleOneNormalNode(node6);
            }
            
            _nodes.TryGetValue(new IntVector2(nodeX + 1, nodeY), out var node7);
            if (node7 != null)
            {
                HandleOneNormalNode(node7);
            }
            
            _nodes.TryGetValue(new IntVector2(nodeX + 1, nodeY - 1), out var node8);
            if (node8 != null)
            {
                HandleOneNormalNode(node8);
            }
        }


        public void ReSet(int width, int height, int landMineCount, Transform parent)
        {
            Dispose();
            Spawn(width,height,landMineCount,parent);
        }
        
        public void Dispose()
        {
            for (int i = 0; i < _nodeList.Count; i++)
            {
                _nodeList[i].Dispose();
            }
            _nodes.Clear();
            _nodeList.Clear();
            _landMineNodePosList.Clear();
        }

        private AbstractNode GetNodeByType(NodeType typeId)
        {
            switch (typeId)
            {
                case NodeType.Normal:return new NormalNode();
                case NodeType.LandMine: return new LandMineNode();
            }

            return null;
        }
        
        
    }
}